package com.example.movie.data.user.model

import android.content.Context
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.example.movie.R
import com.example.movie.common.constants.AppConstants
import com.example.movie.common.constants.Constants
import com.example.movie.common.exception.ClientException
import com.example.movie.common.exception.RemoteServerException
import com.example.movie.common.model.BaseResponse
import com.example.movie.common.model.Result
import com.example.movie.common.model.ResultCode
import com.example.movie.common.request.UserService
import com.example.movie.data.movie.model.bean.ApproveBean
import com.example.movie.data.movie.model.vo.ForumVo
import com.example.movie.data.movie.model.vo.SearchVo
import com.example.movie.data.user.login.model.LoggedInUser
import com.example.movie.data.user.model.vo.OrderVo
import com.example.movie.ui.MainActivity
import com.example.movie.ui.video.bean.VideoVo
import com.example.movie.utils.*
import okhttp3.MultipartBody
import okhttp3.RequestBody
import java.io.IOException
import java.net.UnknownServiceException


/**
 * Class that handles authentication w/ login credentials and retrieves user information.
 */
class UserDataSource {

    private val userService: UserService =
        RequestUtil.getService(UserService::class.java)

    fun login(username: String, password: String): Result<LoggedInUser> {
        return try {
            val res = userService.login(username, password).execute().body()!!
            if (res.success) {
                saveUsernameAndPassword(username, password)
                Result.Success(res.data)
            } else {
                when (res.code) {
                    ResultCode.USER_LOGIN_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("logging error", e.toString())
            Result.Error(IOException("Error logging in", e))
        }
    }

    fun register(username: String, password: String): Result<Any> {
        return try {
            val res = userService.register(username, password).execute().body()!!
            if (res.success) {
                saveUsernameAndPassword(username, password)
                Result.Success("注册成功!")
            } else {
                when (res.code) {
                    ResultCode.USER_HAS_EXITS_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("registering error", e.toString())
            Result.Error(IOException("Error register error", e))
        }
    }

    private fun saveUsernameAndPassword(username: String, password: String) {
        val ctx = ContextHolder.from(MainActivity::class)
        val sharedPref = ctx.getSharedPreferences(
            ctx.getString(R.string.login_store_file_name),
            Context.MODE_PRIVATE
        )
        with(sharedPref.edit()) {
            putString(ctx.getString(R.string.login_username), username)
            putString(ctx.getString(R.string.login_password), password)
            commit();
        }
    }

    /**
     * 清除权限验证数据
     */
    private fun clearUserToken() {
        val ctx = ContextHolder.from(MainActivity::class)
        val sharedPref = ctx.getSharedPreferences(
            ctx.getString(R.string.login_store_file_name),
            Context.MODE_PRIVATE
        )
        with(sharedPref.edit()) {
            clear()
            commit()
        }
    }

    fun logout(): Result<Any> {
        return try {
            val res = userService.logout().execute().body()!!
            if (res.success) {
                clearUserToken()
                Result.Success("注销成功!")
            } else {
                when (res.code) {
                    ResultCode.USER_HAS_EXITS_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("registering error", e.toString())
            Result.Error(IOException("Error register error", e))
        }
    }


    fun addOrder(ids: String, planId: Int): Result<Any> {
        return try {
            val res = userService.addOrder(ids, planId).execute().body()!!
            if (res.success) {
                Result.Success(true)
            } else {
                when (res.code) {
                    ResultCode.USER_LOGIN_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("addOrder error", e.toString())
            Result.Error(IOException("addOrder error", e))
        }

    }


    fun loadUserInfo(): Result<LoggedInUser>? {
        return try {
            val res = userService.myInfo().execute().body()!!
            if (res.success) {
                Result.Success(res.data)
            } else {
                when (res.code) {
                    ResultCode.USER_LOGIN_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("request error", e.toString())
            Result.Error(IOException("request error", e))
        }
    }

    fun saveUserData(user: LoggedInUser, headImage: RequestBody?): Result<Boolean> {
        return try {
            val res: BaseResponse<Any>?
            res = if (headImage != null) {
                val file = MultipartBody.Part.createFormData("file", "file.png", headImage)
                userService.updateUser(user, file).execute().body()!!
            } else {
                userService.updateUser(user, null).execute().body()!!
            }

            if (res.success) {
                Result.Success(true)
            } else {
                when (res.code) {
                    ResultCode.USER_LOGIN_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("request error", e.toString())
            Result.Success(false)
        }

    }

    fun loadMyMovieList(type: Int): Result<List<SearchVo>> {
        return try {
            val res = userService.myMovieList(type).execute().body()!!
            if (res.success) {
                Result.Success(res.data)
            } else {
                when (res.code) {
                    ResultCode.USER_LOGIN_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("request error", e.toString())
            Result.Error(IOException("request error", e))
        }

    }

    @RequiresApi(Build.VERSION_CODES.O)
    fun newOrder(): Result<List<OrderVo>> {
        return try {
            val res = userService.myOrder().execute().body()!!
            if (res.success) {
                val userDao = DbUtil.getInstance().userDao()
                res.data?.let {
                    userDao.deleteAllOrders()
                    userDao.insertOrders(it)
                }

                val orderVos = mutableListOf<OrderVo>()

                val orderIds = userDao.getOrderIdsByState(Constants.OrderState.NOT_GET)
                for (orderId in orderIds) {
                    val ticketOrders = userDao.getTicketOrders(orderId)
                    with(OrderVo()) {
                        val oneTicketOrder = ticketOrders[0]
                        BeanUtils.copyProperties(oneTicketOrder, this)
                        this.leftTime =
                            DateUtil.DurationOfPlayTime("${oneTicketOrder.playDay} ${oneTicketOrder.startTime}")

                        var totalMoney = 0
                        val tickets = mutableListOf<String>()
                        for (order in ticketOrders) {
                            totalMoney += (order.salePrice * AppConstants.RADIX).toInt()
                            tickets.add(order.seatName)
                        }

                        this.tickets = tickets
                        this.totalMoney = (totalMoney * 1.0 / AppConstants.RADIX).toFloat()

                        orderVos.add(this)
                    }
                }

                Result.Success(orderVos)

            } else {
                when (res.code) {
                    ResultCode.USER_LOGIN_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("system error", e.toString())
            Result.Error(IOException("system error", e))
        }
    }


    @RequiresApi(Build.VERSION_CODES.O)
    fun successOrder(): Result<List<OrderVo>>? {
        return try {
            val res = userService.myOrder().execute().body()!!
            if (res.success) {
                val userDao = DbUtil.getInstance().userDao()
                res.data?.let {
                    userDao.deleteAllOrders()
                    userDao.insertOrders(it)
                }

                val orderVos = mutableListOf<OrderVo>()

                val orderIds = userDao.getOrderIdsByState(Constants.OrderState.SUCCESS)
                for (orderId in orderIds) {
                    val ticketOrders = userDao.getTicketOrders(orderId)
                    with(OrderVo()) {
                        val oneTicketOrder = ticketOrders[0]
                        BeanUtils.copyProperties(oneTicketOrder, this)
                        this.leftTime =
                            DateUtil.DurationOfPlayTime("${oneTicketOrder.playDay} ${oneTicketOrder.startTime}")

                        var totalMoney = 0
                        val tickets = mutableListOf<String>()
                        for (order in ticketOrders) {
                            totalMoney += (order.salePrice * AppConstants.RADIX).toInt()
                            tickets.add(order.seatName)
                        }

                        this.tickets = tickets
                        this.totalMoney = (totalMoney * 1.0 / AppConstants.RADIX).toFloat()

                        orderVos.add(this)
                    }
                }

                Result.Success(orderVos)

            } else {
                when (res.code) {
                    ResultCode.USER_LOGIN_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("system error", e.toString())
            Result.Error(IOException("system error", e))
        }
    }

    @RequiresApi(Build.VERSION_CODES.O)
    fun expireOrder(): Result<List<OrderVo>>? {
        return try {
            val res = userService.myOrder().execute().body()!!
            if (res.success) {
                val userDao = DbUtil.getInstance().userDao()
                res.data?.let {
                    userDao.deleteAllOrders()
                    userDao.insertOrders(it)
                }

                val orderVos = mutableListOf<OrderVo>()

                val orderIds = userDao.getOrderIdsByState(Constants.OrderState.EXPIRED)
                for (orderId in orderIds) {
                    val ticketOrders = userDao.getTicketOrders(orderId)
                    with(OrderVo()) {
                        val oneTicketOrder = ticketOrders[0]
                        BeanUtils.copyProperties(oneTicketOrder, this)
                        this.leftTime =
                            DateUtil.DurationOfPlayTime("${oneTicketOrder.playDay} ${oneTicketOrder.startTime}")

                        var totalMoney = 0
                        val tickets = mutableListOf<String>()
                        for (order in ticketOrders) {
                            totalMoney += (order.salePrice * AppConstants.RADIX).toInt()
                            tickets.add(order.seatName)
                        }

                        this.tickets = tickets
                        this.totalMoney = (totalMoney * 1.0 / AppConstants.RADIX).toFloat()

                        orderVos.add(this)
                    }
                }

                Result.Success(orderVos)

            } else {
                when (res.code) {
                    ResultCode.USER_LOGIN_ERROR.value -> throw ClientException(res.message)
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("system error", e.toString())
            Result.Error(IOException("system error", e))
        }

    }

    fun loadVideoData(): Result<List<VideoVo>> {
        return try {
            val res = userService.loadVideoData().execute().body()!!
            if (res.success) {
                Result.Success(res.data)
            } else {
                when (res.code) {
                    ResultCode.REMOTE_SERVER_ERROR.value -> throw RemoteServerException(res.message)
                    else -> throw UnknownServiceException("未知异常!")
                }
            }
        } catch (e: Throwable) {
            Log.e("request error", e.toString())
            Result.Error(IOException("request error", e))
        }
    }

    fun like(vid: Long): Result<Boolean> {
        try {
            val res = userService.like(vid).execute().body()!!
            return Result.Success(res.success)
        } catch (e: IOException) {
            e.printStackTrace()
            return Result.Error(e)
        }
    }

    fun loadForumPage(vid: Long, page: Int, size: Int): Result<BaseResponse<List<ForumVo>>> {
        return try {
            val res = userService.loadForumPage(vid, page, size).execute().body()!!
            Result.Success(res)
        } catch (e: IOException) {
            e.printStackTrace()
            Result.Error(e)
        }
    }

    fun approve(forumId: Int): Result<ApproveBean>? {
        return try {
            val res = userService.approve(forumId).execute().body()!!
            Result.Success(res.data)
        } catch (e: IOException) {
            e.printStackTrace()
            Result.Error(e)
        }
    }

    fun loadReplies(pid: Long, page: Int, size: Int): Result<BaseResponse<List<ForumVo>>>? {
        return try {
            val res = userService.loadReplies(pid, page, size).execute().body()!!
            Result.Success(res)
        } catch (e: IOException) {
            e.printStackTrace()
            Result.Error(e)
        }
    }

    fun addForum(vid: Long, content: String, pid: Int, toId: String?): Result<Int>? {
        return try {
            val res = userService.addForum(vid, content, pid, toId).execute().body()!!
            Result.Success(res.data)
        } catch (e: IOException) {
            e.printStackTrace()
            Result.Error(e)
        }
    }

    fun loadMyLikeMovieVideoList(): Result<List<VideoBean>>? {
        return try {
            val res = userService.loadMyLikeMovieVideoList().execute().body()!!
            Result.Success(res.data)
        } catch (e: IOException) {
            e.printStackTrace()
            Result.Error(e)
        }
    }


}